using System.Collections.Generic;

namespace Tycho.Parser.Peg {
    public class LazyDynamicGrammar : IDynamicGrammar {
        private IDictionary<object, List<IProduction>> InheritedProductions;
        private IDictionary<object, List<IProduction>> StoredProductions;

        public LazyDynamicGrammar () {
            InheritedProductions = null;
            StoredProductions = null;
        }

        public IDynamicGrammar Clone () {
            return new LazyDynamicGrammar () {InheritedProductions = StoredProductions ?? InheritedProductions};
        }

        private IDictionary<object, List<IProduction>> Productions {
            get {
                if (StoredProductions == null) {
                    if (InheritedProductions != null) {
                        StoredProductions = CloneProductions ();
                    } else {
                        StoredProductions = new Dictionary<object, List<IProduction>> ();
                    }
                }

                return StoredProductions;
            }
        }

        public IEnumerable<IProduction> GetChoices (object key) {
            return Productions[key];
        }

        public void AddDynamicChoice (object key, IEnumerable<IProduction> choices) {
            Productions.Add (key, new List<IProduction> (choices));
        }

        private Dictionary<object, List<IProduction>> CloneProductions () {
            var productions = new Dictionary<object, List<IProduction>> ();

            foreach (var keyValue in InheritedProductions) {
                productions.Add (keyValue.Key, new List<IProduction> (keyValue.Value));
            }

            return productions;
        }

        public void InsertChoiceBefore (object key, IProduction beforeProduction, IProduction toInsert) {
            List<IProduction> choices = Productions [key];
            int index = choices.IndexOf (beforeProduction);
            choices.Insert (index, toInsert);
        }

        public void InsertChoiceFirst (object key, IProduction toInsert) {
            List<IProduction> choices = Productions [key];
            choices.Insert (0, toInsert);
        }

        public void InsertChoiceAfter (object key, IProduction afterProduction, IProduction toInsert) {
            List<IProduction> choices = Productions [key];
            int index = choices.IndexOf (afterProduction) + 1;
            choices.Insert (index, toInsert);
        }

        public void InsertChoiceLast (object key, IProduction toInsert) {
            List<IProduction> choices = Productions [key];
            choices.Add (toInsert);
        }

        public bool HasDynamicChoice (object key) {
            return Productions.ContainsKey (key);
        }
    }
}